using System.Collections.Generic;
using Newtonsoft.Json;


namespace HEFramework
{
    public enum eAssetBundleDownloadState
    {
        Check, //检测
        DownLoad, //下载
        Completed, //完成
    }

    /// <summary>
    ///
    /// AB下载器
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-12-28 17:00:09
    /// ----------------------------------------
    /// </summary>
    public class AssetBundleDownloader : Singleton<AssetBundleDownloader>, ISingletonAwake
    {
        /// <summary>
        /// 最大重连次数
        /// </summary>
        public const int RETRY_MAX_COUNT = 30;


        /// <summary>
        /// 缓冲Buffer大小
        /// </summary>
        public const int BUFFER_SIZE = 1024 * 256;


        /// <summary>
        /// 是否完成
        /// </summary>
        public eAssetBundleDownloadState State { get; set; }

        /// <summary>
        /// 已检测完的文件
        /// </summary>
        public int ReadyCheckCount { get; set; }

        /// <summary>
        /// 总需要检测的文件
        /// </summary>
        public int TotalCheckCount { get; set; }

        /// <summary>
        /// 已下载字节
        /// </summary>
        public int ReadyDownLoadByte { get; set; }

        /// <summary>
        /// 总需要下载字节
        /// </summary>
        public int TotalDownLoadByte { get; set; }

        /// <summary>
        /// 重传次数
        /// </summary>
        public int RetryCount { get; set; }

        /// <summary>
        /// 加解密工具
        /// </summary>
        private Aes aes;

        /// <summary>
        /// 数据信息
        /// </summary>
        private List<FileCheckList.FileCheckData> datas = new();

        /// <summary>
        /// 数据
        /// </summary>
        AssetBundleSettingScriptableObject data = AssetBundleSettingScriptableObject.Instance;

        //临时计算用变量
        private string abName;
        private string filePath;
        private string url;
        private byte[] bytes;

        /// <summary>
        /// 初始化
        /// </summary>
        public void Awake()
        {
            //仅能在Persistent环境下执行
            if (data.Domain != eDomain.Persistent)
            {
                return;
            }

            if (data.Encrypt)
            {
                aes = new Aes(data.Key, data.IV);
            }
            else
            {
                aes = null;
            }
        }

        protected override void Destroy()
        {
            datas.Clear();
        }


        /// <summary>
        /// 更新文件
        /// </summary>
        public async HETask UpdateFile()
        {
            //仅能在Persistent环境下执行
            if (data.Domain != eDomain.Persistent)
            {
                return;
            }

            Log.Debug("Start AB[Check]");
            State = eAssetBundleDownloadState.Check;
            ReadyCheckCount = 0;
            TotalCheckCount = 0;
            ReadyDownLoadByte = 0;
            TotalDownLoadByte = 0;
            RetryCount = 0;
            datas.Clear();

            //file.check文件下载验证
            abName = data.AssetBundleCheckFileName;
            if (data.Encrypt)
            {
                abName = MD5Hash.ComputeHashToHex(abName);
            }

            //下载
            url = data.AssetBundleDataDownloadURL + "/" + data.AssetBundleDataDomainFolder + "/" + data.GetPlatform() + "/" + abName;
            bytes = await HTTP.Get(url);
            if (bytes.Length <= 0)
            {
                Log.Error("AB[Check] error");
                return;
            }

            //写入
            filePath = data.GetAssetBundleDataLoadPath() + "/" + abName;
            await File.WriteBytesAsync(filePath, bytes, null, null, BUFFER_SIZE);


            if (data.Encrypt)
            {
                bytes = await aes.DecryptAsync(bytes, null, BUFFER_SIZE);
            }

            string json = System.Text.Encoding.UTF8.GetString(bytes);
            FileCheckList checkFile = JsonConvert.DeserializeObject<FileCheckList>(json);

            TotalCheckCount = checkFile.Datas.Count;


            //文件验证比对
            for (int i = 0; i < TotalCheckCount; i++)
            {
                int index = i;
                var checkData = checkFile.Datas[index];
                Log.Debug("Check AB ->" + checkData.Symbol);
                abName = checkData.Symbol;
                filePath = data.GetAssetBundleDataLoadPath() + "/" + abName;
                //查找本地文件，并且对比
                if (File.CheckFile(filePath))
                {
                    byte[] datas = await File.ReadBytesAsync(filePath, null, null, BUFFER_SIZE);
                    string hash = MD5Hash.ComputeHashToHex(datas);

                    //哈希值对不上,字节数对不上 需更新
                    if (hash != checkData.Hash || datas.Length != checkData.BytesLength)
                    {
                        this.datas.Add(checkFile.Datas[index]);
                    }
                }
                else
                {
                    //未存在该文件 加入下载列表
                    datas.Add(checkData);
                }

                ReadyCheckCount++;
            }


            //------------------------------------------------------------------------------------------------------------------------------------------------
            Log.Debug("Start AB[Down]");
            State = eAssetBundleDownloadState.DownLoad;
            //无更新
            if (datas.Count == 0)
            {
                State = eAssetBundleDownloadState.Completed;
                Log.Debug("Not file update!");
                return;
            }

            //计算要下载的字节总长度
            for (int i = 0; i < datas.Count; i++)
            {
                TotalDownLoadByte += datas[i].BytesLength;
            }


            await Retry();
        }


        /// <summary>
        /// 重新尝试
        /// </summary>
        private async HETask Retry()
        {
            //已下载完成或重连次数超了
            if (datas.Count == 0)
            {
                Log.Debug("AB[Down] completed");
                return;
            }

            if (RetryCount > RETRY_MAX_COUNT)
            {
                Log.Error("Retry out times");
                return;
            }

            bool isNeedRetry = false;
            List<FileCheckList.FileCheckData> succeeds = new List<FileCheckList.FileCheckData>();

            //开始下载
            for (int i = 0; i < datas.Count; i++)
            {
                abName = datas[i].Symbol;
                url = data.AssetBundleDataDownloadURL + "/" + data.AssetBundleDataDomainFolder + "/" + data.GetPlatform() + "/" + abName;
                bytes = await HTTP.Get(url);
                if (bytes.Length <= 0)
                {
                    isNeedRetry = true;
                }
                else
                {
                    filePath = data.GetAssetBundleDataLoadPath() + "/" + abName;
                    await File.WriteBytesAsync(filePath, bytes, null, null, BUFFER_SIZE);
                    ReadyDownLoadByte += datas[i].BytesLength;
                    succeeds.Add(datas[i]);
                }
            }

            for (int i = 0; i < succeeds.Count; i++)
            {
                datas.Remove(succeeds[i]);
            }

            succeeds.Clear();

            if (isNeedRetry)
            {
                RetryCount++;
                await Retry();
            }

            if (datas.Count == 0)
            {
                Log.Debug("AB[Down] completed");
            }
        }
    }
}